/*
 * comtradereader.cpp
 *
 *  Created on: 2019年11月14日
 *      Author: turne
 */

#include <dm/app/comtradereader.hpp>

#include <dm/exception.hpp>
#include <dm/os/log/logger.hpp>
#include <dm/datetime.hpp>
#include <dm/bits.hpp>
#include <dm/string/stringlist.hpp>
#include <string>

namespace dm{
namespace app{

static const char* logModule = "CComtradeReader.app.dm";

using namespace std;

static bool readLine( istream& istr,dm::string::CStringList& sl ){
	static char buf[1024];
	istr.getline(buf,1023);
	if( istr.eof() )
		return false;
	sl.split(buf,',');
	return true;
}

static bool inputTsAscii(istream& istr,dm::CTimeStamp& ts ){
	char buf[1024];
	istr.getline(buf,1023);
	if( istr.eof() )
		return false;

	int d,m,y,h,min;
	float s;

	if( 6!=sscanf(buf,"%d/%d/%d,%d:%d:%f",&d,&m,&y,&h,&min,&s))
		return false;

	dm::CDateTime dt;
	dt.setYear(y);
	dt.setMonth(m);
	dt.setDay(d);
	dt.setHour(h);
	dt.setMinute(min);
	dt.setSec(s);

	ts = dt.toTimeStamp();
	ts.setUseconds( int((s*1000000L)) % 1000000 );

	return true;
}

CComtradeReader::CComtradeReader():CComtradeFiles(),m_index(0){
	log().debug(THISMODULE "创建对象");
}

CComtradeReader::~CComtradeReader(){
	if( m_istr.is_open() ){
		log().info(THISMODULE "关闭文件");
		m_istr.close();
	}else{
		log().debug(THISMODULE "销毁对象");
	}
}

/**
 * 加载录波信息
 * 读取配置文件，并打开数据文件
 * @return
 */
bool CComtradeReader::load(){
	if( m_istr.is_open() ){
		log().info(THISMODULE "文件已经打开");
		m_istr.close();
	}

	if( name()==NULL ){
		log().warnning(THISMODULE "为设置名称");
		return false;
	}

	std::string file = name();
	file += ".cfg";
	if( dir() ){
		if( dm::string::CStringRef(dir()).isEndWith("/\\") )
			file = dir() + file;
		else{
			file = '/' + file;
			file = dir() + file;
		}
	}

	ifstream istr;
	istr.open(file.c_str());
	if( !istr.is_open() ){
		log().warnning(THISMODULE "打开配置文件%s失败",file.c_str());
		return false;
	}

	try{
		dm::string::CStringList sl;

		if( !readLine(istr,sl) || sl.size()!=3 ){
			log().warnning(THISMODULE "读取站名行失败 %d",sl.size());
			throw dm::CException();
		}

		sl.at(0).dumpAutoMalloc(&m_stationName);
		sl.at(1).dumpAutoMalloc(&m_recDevId);
		m_revYear = sl.at(2).trimed().toInt16();

		if( !readLine(istr,sl) || sl.size()!=3 ){
			log().warnning(THISMODULE "读取通道数量行失败");
			throw dm::CException();
		}

		int i = sl.at(0).toInt32();
		int ia,id;
		if( !sl.at(1).getFormated("%dA",ia) ){
			log().warnning(THISMODULE "读取模拟通道数失败");
			throw dm::CException();
		}

		if( !sl.at(2).getFormated("%dD",id) ){
			log().warnning(THISMODULE "读取状态通道数失败");
			throw dm::CException();
		}

		if( i!=(ia+id) ){
			log().warnning(THISMODULE "通道数和不正确%d!=%d+%d",i,ia,id);
			throw dm::CException();
		}

		// 测量量信息
		for( i=0;i<ia;++i ){
			if( !readLine(istr,sl) || sl.size()!=13 ){
				log().warnning(THISMODULE "测量量%d信息错误",i);
				throw dm::CException();
			}

			CMeasureInfo m;
			int p = 0;

			if( sl.at(p++).toInt32()!=(i+1) ){
				log().warnning(THISMODULE "测量量%d序号错误%s",i,sl.at(0).c_str());
				throw dm::CException();
			}

			m.setChId(sl.at(p++).c_str());
			m.setPh( sl.at(p++).c_str());
			m.setCcbm(sl.at(p++).c_str());

			m.setUu(sl.at(p++).c_str());
			m.setA( sl.at(p++).toFloat32());
			m.setB( sl.at(p++).toFloat32());
			m.setSkew( sl.at(p++).toFloat32() );

			m.setMin(sl.at(p++).toInt32());
			m.setMax(sl.at(p++).toInt32());

			m.setPrimary( sl.at(p++).toFloat32() );
			m.setSecondary( sl.at(p++).toFloat32() );

			m.setPs(sl.at(p++).trimed().c_str()[0]);

			m_measures.push_back(m);
		}

		// 状态量信息
		for( i=0;i<id;++i ){
			if( !readLine(istr,sl) || sl.size()!=5 ){
				log().warnning(THISMODULE "状态量%d信息错误",i);
				throw dm::CException();
			}

			CStatusInfo s;
			int p = 0;

			if( sl.at(p++).toInt32()!=(i+1) ){
				log().warnning(THISMODULE "状态量%d序号错误%s",i,sl.at(0).c_str());
				throw dm::CException();
			}

			s.setChId(sl.at(p++).c_str());
			s.setPh(sl.at(p++).c_str());
			s.setCcbm(sl.at(p++).c_str());

			s.setY(sl.at(p++).trimed().toInt32()==1);

			m_status.push_back(s);
		}

		// 电网频率
		if( !readLine(istr,sl) || sl.size()>1 ){
			log().warnning(THISMODULE "电网频率行错误");
			throw dm::CException();
		}

		if( sl.size()==1 )
			m_if = sl.at(0).trimed().toFloat32();

		// 采样速率数
		if( !readLine(istr,sl) || sl.size()!=1 ){
			log().warnning(THISMODULE "采样速率配置数错误");
			throw dm::CException();
		}

		int nrate = sl.at(0).trimed().toInt32();
		if( nrate<1 ){
			log().warnning(THISMODULE "采样速率配置数%d错误",nrate);
			throw dm::CException();
		}

		for( i=0;i<nrate;++i ){
			if( !readLine(istr,sl) || sl.size()!=2 ){
				log().warnning(THISMODULE "采样速率配置项%d错误",i);
				throw dm::CException();
			}

			m_rates.push_back(CRate(sl.at(0).toFloat32(),sl.at(1).trimed().toInt32()));
		}

		// 日期时标
		if( !inputTsAscii(istr,m_tsStart) ){
			log().warnning(THISMODULE "数据开始时标错误");
			throw dm::CException();
		}

		if( !inputTsAscii(istr,m_tsTrig) ){
			log().warnning(THISMODULE "故障触发时标错误");
			throw dm::CException();
		}

		// 数据类型
		if( !readLine(istr,sl) || sl.size()!=1 ){
			log().warnning(THISMODULE "数据文件格式错误");
			throw dm::CException();
		}

		dm::string::CString ft = sl.at(0).trimed();
		if( ft=="BINARY" || ft=="binary" )
			m_ft = FormatBinary;
		else if( ft=="ASCII" || ft=="ascii" )
			m_ft = FormatAscii;
		else{
			log().warnning(THISMODULE "未知数据类型%s",sl.at(0).c_str());
			throw dm::CException();
		}

		// 时标倍率因子
		if( !readLine(istr,sl) || sl.size()!=1 ){
			log().warnning(THISMODULE "时标倍率因子错误");
			throw dm::CException();
		}

		m_timeMult = sl.at(0).trimed().toFloat32();
	}catch(dm::CException& e ){
		log().warnning(THISMODULE e.what());
		istr.close();
		return false;
	}

	istr.close();

	// 打开数据文件
	file = name();
	file += ".dat";
	if( dir() ){
		if( dm::string::CStringRef(dir()).isEndWith("/\\") )
			file = dir() + file;
		else{
			file = '/'+file;
			file = dir() + file;
		}
	}

	if( m_ft==FormatBinary )
		m_istr.open(file.c_str(),ifstream::binary);
	else
		m_istr.open(file.c_str());

	if( !m_istr.is_open() ){
		log().warnning(THISMODULE "打开数据文件%s失败",file.c_str());
		return false;
	}

	m_index = 1;

	return true;
}

template<typename T>
static inline void inputBinary( istream& istr,T& v ){
	istr.read((char*)&v,sizeof(v));
}

/**
 * 顺序读取数据记录
 * @param measures
 * @param measureSize
 * @param status
 * @param statusSize
 * @param ts
 * @return
 */
bool CComtradeReader::getNext( measure_t* measures,int measureSize,status_t* status,int statusSize,dm::CTimeStamp* ts ){
	if( !m_istr.is_open() || m_istr.eof() ){
		log().info(THISMODULE "数据文件未打开或者已经结束");
		return false;
	}

	if( measureSize!=(int)m_measures.size() ){
		log().info(THISMODULE "测量量参数个数%d错误%d",measureSize,m_measures.size());
		return false;
	}

	if( statusSize!=(int)m_status.size() ){
		log().info(THISMODULE "状态量参数个数%d错误%d",statusSize,m_status.size());
		return false;
	}

	if( m_ft==FormatAscii ){
		dm::string::CStringList sl;
		if( !readLine(m_istr,sl) ){
			log().warnning(THISMODULE "读取数据文件失败%d",m_index);
			return false;
		}

		if( (unsigned)sl.size()!=(m_measures.size()+m_status.size()+2) ){
			log().warnning(THISMODULE "数据格式错误%d",m_index);
			return false;
		}


		if( sl.at(0).toUint32()!=m_index ){
			log().warnning(THISMODULE "数据行号%s不符%d",sl.at(0).c_str(),m_index);
			return false;
		}

		++m_index;

		// 时标
		if( ts ){
			*ts = m_tsStart;
			if( sl.at(1).len()>0 )
				ts->addUs(sl.at(1).toInt32()*m_timeMult);
			else{
				ts->addUs(m_index*(1000000/m_rates[0].samp()));
			}
		}

		int p = 2;
		for( int i=0;i<measureSize;++i )
			measures[i] = sl.at(p++).trimed().toInt32();

		for( int i=0;i<statusSize;++i )
			status[i] = sl.at(p++).trimed().toInt32();

		return true;
	}else if( m_ft==FormatBinary ){
		dm::uint32 i32;

		inputBinary(m_istr,i32);

		if( m_istr.eof() ){
			log().warnning(THISMODULE "读取序号失败%d",m_index);
			return false;
		}

		if( i32!=m_index ){
			log().warnning(THISMODULE "序号%d不正确%d",i32,m_index);
			return false;
		}

		if( m_istr.eof() ){
			log().warnning(THISMODULE "读取时标失败%d",m_index);
			return false;
		}

		++m_index;

		inputBinary(m_istr,i32);

		if( ts ){
			*ts = m_tsStart;
			if( i32!=0 ){
				ts->addUs(i32*m_timeMult);
			}else{
				ts->addUs(m_index*(1000000/m_rates[0].samp()));
			}
		}

		for( unsigned int i=0;i<m_measures.size();++i ){
			if( m_istr.eof() ){
				log().warnning(THISMODULE "读取测量量%d失败",i);
				return true;
			}
			inputBinary(m_istr,measures[i]);
		}

		for( unsigned int i=0;i<m_status.size();++i ){
			dm::uint16 u16;

			if( m_istr.eof() ){
				log().warnning(THISMODULE "读取低%d状态量失败",i);
				return true;
			}
			inputBinary(m_istr,u16);

			for( int b=0;b<16;++b ){
				status[i] = dm::bit_get(u16,b);
				++i;
				if( i>=m_status.size() )
					break;
			}
		}

		return true;
	}else{
		log().warnning(THISMODULE "未知格式%d",m_ft);
		return false;
	}

	return false;
}

}
}

